home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectSound / StreamData / streamdata.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-31  |  16.1 KB  |  470 lines

  1. //----------------------------------------------------------------------------
  2. // File: StreamData.cpp
  3. //
  4. // Desc: The StreamData sample shows how to streaming wave data into 
  5. //       a DirectSound buffer.
  6. //
  7. // Copyright (c) 1999-2001 Microsoft Corp. All rights reserved.
  8. //-----------------------------------------------------------------------------
  9. #define STRICT
  10. #include <windows.h>
  11. #include <basetsd.h>
  12. #include <commdlg.h>
  13. #include <mmreg.h>
  14. #include <dxerr8.h>
  15. #include <dsound.h>
  16. #include "resource.h"
  17. #include "DSUtil.h"
  18.  
  19.  
  20.  
  21.  
  22. //-----------------------------------------------------------------------------
  23. // Function-prototypes
  24. //-----------------------------------------------------------------------------
  25. INT_PTR CALLBACK MainDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
  26. DWORD WINAPI NotificationProc( LPVOID lpParameter );
  27. VOID    OnInitDialog( HWND hDlg );
  28. HRESULT InitDirectSound( HWND hDlg );
  29. HRESULT FreeDirectSound();
  30. VOID    OnOpenSoundFile( HWND hDlg );
  31. VOID    LoadWaveAndCreateBuffer( HWND hDlg, TCHAR* strFileName );
  32. HRESULT InitDSoundNotification();
  33. HRESULT PlayBuffer( BOOL bLooped );
  34. HRESULT HandleNotification( BOOL bLooped );
  35. VOID    OnTimer( HWND hDlg );
  36. VOID    EnablePlayUI( HWND hDlg, BOOL bEnable );
  37.  
  38.  
  39.  
  40.  
  41. //-----------------------------------------------------------------------------
  42. // Defines, constants, and global variables
  43. //-----------------------------------------------------------------------------
  44. #define NUM_PLAY_NOTIFICATIONS  16
  45.  
  46. #define SAFE_DELETE(p)  { if(p) { delete (p);     (p)=NULL; } }
  47. #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
  48.  
  49. CSoundManager*      g_pSoundManager         = NULL;
  50. CStreamingSound*    g_pStreamingSound       = NULL;
  51. HANDLE              g_hNotificationEvent    = NULL;
  52. DWORD               g_dwNotifyThreadID      = 0;
  53. HANDLE              g_hNotifyThread         = NULL;
  54. HINSTANCE           g_hInst                 = NULL;
  55.  
  56.  
  57.  
  58.  
  59. //-----------------------------------------------------------------------------
  60. // Name: WinMain()
  61. // Desc: Entry point for the application.  Since we use a simple dialog for 
  62. //       user interaction we don't need to pump messages.
  63. //-----------------------------------------------------------------------------
  64. INT APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, 
  65.                       INT nCmdShow )
  66. {
  67.     g_hInst = hInst;
  68.     g_hNotificationEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
  69.  
  70.     // Display the main dialog box.
  71.     DialogBox( hInst, MAKEINTRESOURCE(IDD_MAIN), NULL, MainDlgProc );
  72.  
  73.     CloseHandle( g_hNotificationEvent );
  74.  
  75.     return TRUE;
  76. }
  77.  
  78.  
  79.  
  80.  
  81. //-----------------------------------------------------------------------------
  82. // Name: NotificationProc()
  83. // Desc: Handles dsound notifcation events
  84. //-----------------------------------------------------------------------------
  85. DWORD WINAPI NotificationProc( LPVOID lpParameter )
  86. {
  87.     HRESULT hr;
  88.     HWND    hDlg = (HWND) lpParameter;
  89.     MSG     msg;
  90.     DWORD   dwResult;
  91.     BOOL    bDone = FALSE;
  92.     BOOL    bLooped;
  93.  
  94.     while( !bDone ) 
  95.     { 
  96.         dwResult = MsgWaitForMultipleObjects( 1, &g_hNotificationEvent, 
  97.                                               FALSE, INFINITE, QS_ALLEVENTS );
  98.         switch( dwResult )
  99.         {
  100.             case WAIT_OBJECT_0 + 0:
  101.                 // g_hNotificationEvent is signaled
  102.  
  103.                 // This means that DirectSound just finished playing 
  104.                 // a piece of the buffer, so we need to fill the circular 
  105.                 // buffer with new sound from the wav file
  106.                 bLooped = ( IsDlgButtonChecked( hDlg, IDC_LOOP_CHECK ) == BST_CHECKED );
  107.                 if( FAILED( hr = g_pStreamingSound->HandleWaveStreamNotification( bLooped ) ) )
  108.                 {
  109.                     DXTRACE_ERR( TEXT("HandleWaveStreamNotification"), hr );
  110.                     MessageBox( hDlg, "Error handling DirectSound notifications."
  111.                                "Sample will now exit.", "DirectSound Sample", 
  112.                                MB_OK | MB_ICONERROR );
  113.                     bDone = TRUE;
  114.                 }
  115.  
  116.                 break;
  117.  
  118.             case WAIT_OBJECT_0 + 1:
  119.                 // Messages are available
  120.                 while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) 
  121.                 { 
  122.                     if( msg.message == WM_QUIT )
  123.                         bDone = TRUE;
  124.                 }
  125.                 break;
  126.         }
  127.     }
  128.  
  129.     return 0;
  130. }
  131.  
  132.  
  133.  
  134.  
  135. //-----------------------------------------------------------------------------
  136. // Name: MainDlgProc()
  137. // Desc: Handles dialog messages
  138. //-----------------------------------------------------------------------------
  139. INT_PTR CALLBACK MainDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
  140. {
  141.     HRESULT hr;
  142.  
  143.     switch (msg) 
  144.     {
  145.     case WM_INITDIALOG:
  146.         OnInitDialog( hDlg );
  147.         break;
  148.  
  149.     case WM_COMMAND:
  150.         switch ( LOWORD(wParam) )
  151.         {
  152.             case IDC_SOUNDFILE:
  153.                 OnOpenSoundFile( hDlg );
  154.                 break;
  155.  
  156.             case IDCANCEL:
  157.                 PostQuitMessage( 0 );
  158.                 EndDialog( hDlg, IDCANCEL );
  159.                 break;
  160.  
  161.             case IDC_PLAY:
  162.                 {
  163.                     BOOL bLooped = ( IsDlgButtonChecked( hDlg, IDC_LOOP_CHECK ) == BST_CHECKED );
  164.  
  165.                     if( FAILED( hr = PlayBuffer( bLooped ) ) )
  166.                     {
  167.                         DXTRACE_ERR( TEXT("PlayBuffer"), hr );
  168.                         MessageBox( hDlg, "Error playing DirectSound buffer."
  169.                                     "Sample will now exit.", "DirectSound Sample", 
  170.                                     MB_OK | MB_ICONERROR );
  171.                         EndDialog( hDlg, IDABORT );
  172.                     }
  173.  
  174.                     // Update the UI controls to show the sound as playing
  175.                     EnablePlayUI( hDlg, FALSE );
  176.                 }
  177.                 break;
  178.  
  179.             case IDC_STOP:
  180.                 if( g_pStreamingSound )
  181.                 {
  182.                     g_pStreamingSound->Stop();
  183.                     g_pStreamingSound->Reset();
  184.                 }
  185.  
  186.                 EnablePlayUI( hDlg, TRUE );
  187.                 break;
  188.  
  189.             default:
  190.                 return FALSE; // Didn't handle message
  191.         }
  192.         break;
  193.  
  194.     case WM_TIMER:
  195.         OnTimer( hDlg );
  196.         break;
  197.  
  198.     case WM_DESTROY:
  199.         // Cleanup everything
  200.         KillTimer( hDlg, 1 );    
  201.         SAFE_DELETE( g_pStreamingSound );
  202.         SAFE_DELETE( g_pSoundManager );
  203.  
  204.         // Close down notification thread
  205.         PostThreadMessage( g_dwNotifyThreadID, WM_QUIT, 0, 0 );
  206.         WaitForSingleObject( g_hNotifyThread, INFINITE );
  207.         CloseHandle( g_hNotifyThread );
  208.         break; 
  209.  
  210.     default:
  211.         return FALSE; // Didn't handle message
  212.     }
  213.  
  214.     return TRUE; // Handled message
  215. }
  216.  
  217.  
  218.  
  219.  
  220. //-----------------------------------------------------------------------------
  221. // Name: OnInitDialog()
  222. // Desc: Initializes the dialogs (sets up UI controls, etc.)
  223. //-----------------------------------------------------------------------------
  224. VOID OnInitDialog( HWND hDlg )
  225. {
  226.     HRESULT hr;
  227.  
  228.     // Load the icon
  229.     HICON hIcon = LoadIcon( g_hInst, MAKEINTRESOURCE( IDR_MAINFRAME ) );
  230.  
  231.     // Set the icon for this dialog.
  232.     SendMessage( hDlg, WM_SETICON, ICON_BIG,   (LPARAM) hIcon );  // Set big icon
  233.     SendMessage( hDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIcon );  // Set small icon
  234.  
  235.     // Create a static IDirectSound in the CSound class.  
  236.     // Set coop level to DSSCL_PRIORITY, and set primary buffer 
  237.     // format to stereo, 22kHz and 16-bit output.
  238.     g_pSoundManager = new CSoundManager();
  239.  
  240.     if( FAILED( hr = g_pSoundManager->Initialize( hDlg, DSSCL_PRIORITY, 2, 22050, 16 ) ) )
  241.     {
  242.         DXTRACE_ERR( TEXT("Initialize"), hr );
  243.         MessageBox( hDlg, "Error initializing DirectSound.  Sample will now exit.", 
  244.                           "DirectSound Sample", MB_OK | MB_ICONERROR );
  245.         EndDialog( hDlg, IDABORT );
  246.         return;
  247.     }
  248.  
  249.     // Create a thread to handle DSound notifications
  250.     g_hNotifyThread = CreateThread( NULL, 0, NotificationProc, 
  251.                                     hDlg, 0, &g_dwNotifyThreadID );
  252.  
  253.     // Create a timer, so we can check for when the soundbuffer is stopped
  254.     SetTimer( hDlg, 0, 250, NULL );
  255.  
  256.     // Set the UI controls
  257.     SetDlgItemText( hDlg, IDC_FILENAME, TEXT("No file loaded.") );
  258. }
  259.  
  260.  
  261.  
  262.  
  263. //-----------------------------------------------------------------------------
  264. // Name: OnOpenSoundFile()
  265. // Desc: Called when the user requests to open a sound file
  266. //-----------------------------------------------------------------------------
  267. VOID OnOpenSoundFile( HWND hDlg ) 
  268. {
  269.     static TCHAR strFileName[MAX_PATH] = TEXT("");
  270.     static TCHAR strPath[MAX_PATH] = TEXT("");
  271.  
  272.     // Setup the OPENFILENAME structure
  273.     OPENFILENAME ofn = { sizeof(OPENFILENAME), hDlg, NULL,
  274.                          TEXT("Wave Files\0*.wav\0All Files\0*.*\0\0"), NULL,
  275.                          0, 1, strFileName, MAX_PATH, NULL, 0, strPath,
  276.                          TEXT("Open Sound File"),
  277.                          OFN_FILEMUSTEXIST|OFN_HIDEREADONLY, 0, 0,
  278.                          TEXT(".wav"), 0, NULL, NULL };
  279.  
  280.     // Get the default media path (something like C:\WINDOWS\MEDIA)
  281.     if( '\0' == strPath[0] )
  282.     {
  283.         GetWindowsDirectory( strPath, MAX_PATH );
  284.         if( strcmp( &strPath[strlen(strPath)], TEXT("\\") ))
  285.             strcat( strPath, TEXT("\\") );
  286.         strcat( strPath, TEXT("MEDIA") );
  287.     }
  288.  
  289.     if( g_pStreamingSound )
  290.     {
  291.         g_pStreamingSound->Stop();
  292.         g_pStreamingSound->Reset();
  293.     }
  294.  
  295.     // Update the UI controls to show the sound as loading a file
  296.     EnableWindow( GetDlgItem( hDlg, IDC_LOOP_CHECK ), FALSE );
  297.     EnableWindow( GetDlgItem( hDlg, IDC_PLAY ),       FALSE );
  298.     EnableWindow( GetDlgItem( hDlg, IDC_STOP ),       FALSE );
  299.     SetDlgItemText( hDlg, IDC_FILENAME, TEXT("Loading file...") );
  300.  
  301.     // Display the OpenFileName dialog. Then, try to load the specified file
  302.     if( TRUE != GetOpenFileName( &ofn ) )
  303.     {
  304.         SetDlgItemText( hDlg, IDC_FILENAME, TEXT("Load aborted.") );
  305.         return;
  306.     }
  307.  
  308.     SetDlgItemText( hDlg, IDC_FILENAME, TEXT("") );
  309.  
  310.     // Load the wave file and create a DirectSound buffer
  311.     LoadWaveAndCreateBuffer( hDlg, strFileName );
  312.  
  313.     // Remember the path for next time
  314.     strcpy( strPath, strFileName );
  315.     char* strLastSlash = strrchr( strPath, '\\' );
  316.     strLastSlash[0] = '\0';
  317. }
  318.  
  319.  
  320.  
  321.  
  322.  
  323. //-----------------------------------------------------------------------------
  324. // Name: LoadWaveAndCreateBuffer()
  325. // Desc: Loads the wave file, and create a DirectSound buffer.  Since we are
  326. //       streaming data into the buffer, the buffer will be filled with data 
  327. //       when the sound is played, and as notification events are signaled
  328. //-----------------------------------------------------------------------------
  329. VOID LoadWaveAndCreateBuffer( HWND hDlg, TCHAR* strFileName )
  330. {
  331.     HRESULT   hr;
  332.     CWaveFile waveFile;
  333.     DWORD     dwNotifySize;
  334.  
  335.     // Load the wave file
  336.     if( FAILED( hr = waveFile.Open( strFileName, NULL, WAVEFILE_READ ) ) )
  337.     {
  338.         DXTRACE_ERR( TEXT("Open"), hr );
  339.         waveFile.Close();
  340.         SetDlgItemText( hDlg, IDC_FILENAME, TEXT("Bad wave file.") );
  341.         return;
  342.     }
  343.  
  344.     if( waveFile.GetSize() == 0 )
  345.     {
  346.         waveFile.Close();
  347.         SetDlgItemText( hDlg, IDC_FILENAME, TEXT("Wave file blank.") );
  348.         return;
  349.     }
  350.  
  351.     // The wave file is valid, and waveFile.m_pwfx is the wave's format
  352.     // so we are done with the reader.
  353.     waveFile.Close();
  354.  
  355.     // This samples works by dividing a 3 second streaming buffer into 
  356.     // NUM_PLAY_NOTIFICATIONS (16) pieces.  It creates a notification for each
  357.     // piece and when a notification arrives then it fills the circular streaming 
  358.     // buffer with new wav data over the sound data which was just played
  359.  
  360.     // Determine the g_dwNotifySize.  It should be an integer multiple of nBlockAlign
  361.     DWORD nBlockAlign = (DWORD)waveFile.m_pwfx->nBlockAlign;
  362.     INT nSamplesPerSec = waveFile.m_pwfx->nSamplesPerSec;
  363.     dwNotifySize = nSamplesPerSec * 3 * nBlockAlign / NUM_PLAY_NOTIFICATIONS;
  364.     dwNotifySize -= dwNotifySize % nBlockAlign;   
  365.  
  366.     // Create a new sound
  367.     SAFE_DELETE( g_pStreamingSound );
  368.  
  369.     // Set up the direct sound buffer.  Request the NOTIFY flag, so
  370.     // that we are notified as the sound buffer plays.  Note, that using this flag
  371.     // may limit the amount of hardware acceleration that can occur. 
  372.     if( FAILED( hr = g_pSoundManager->CreateStreaming( &g_pStreamingSound, strFileName, 
  373.                                                   DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GETCURRENTPOSITION2, 
  374.                                                   GUID_NULL, NUM_PLAY_NOTIFICATIONS, 
  375.                                                   dwNotifySize, g_hNotificationEvent ) ) )
  376.     {
  377.         if( hr != DSERR_BADFORMAT && hr != E_INVALIDARG )
  378.             DXTRACE_ERR( TEXT("CreateStreaming"), hr );
  379.  
  380.         SetDlgItemText( hDlg, IDC_FILENAME, TEXT("Could not create sound buffer.") );
  381.         return;
  382.     }
  383.  
  384.     // Update the UI controls to show the sound as the file is loaded
  385.     EnablePlayUI( hDlg, TRUE );
  386.     SetDlgItemText( hDlg, IDC_FILENAME, strFileName );
  387. }
  388.  
  389.  
  390.  
  391.  
  392. //-----------------------------------------------------------------------------
  393. // Name: PlayBuffer()
  394. // Desc: Reset the buffer, fill it with sound, and starting it playing
  395. //-----------------------------------------------------------------------------
  396. HRESULT PlayBuffer( BOOL bLooped )
  397. {
  398.     HRESULT hr;
  399.     
  400.     if( NULL == g_pStreamingSound )
  401.         return E_FAIL; // Sanity check
  402.  
  403.     if( FAILED( hr = g_pStreamingSound->Reset() ) )
  404.         return DXTRACE_ERR( TEXT("Reset"), hr );
  405.  
  406.     // Fill the entire buffer with wave data, and if the wav file is small then
  407.     // repeat the wav file if the user wants to loop the file, otherwise fill in
  408.     // silence 
  409.     LPDIRECTSOUNDBUFFER pDSB = g_pStreamingSound->GetBuffer( 0 );
  410.     if( FAILED( hr = g_pStreamingSound->FillBufferWithSound( pDSB, bLooped ) ) )
  411.         return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
  412.  
  413.     // Always play with the LOOPING flag since the streaming buffer
  414.     // wraps around before the entire WAV is played
  415.     if( FAILED( hr = g_pStreamingSound->Play( 0, DSBPLAY_LOOPING ) ) )
  416.         return DXTRACE_ERR( TEXT("Play"), hr );
  417.  
  418.     return S_OK;
  419. }
  420.  
  421.  
  422.  
  423.  
  424. //-----------------------------------------------------------------------------
  425. // Name: OnTimer()
  426. // Desc: When we think the sound is playing this periodically checks to see if 
  427. //       the sound has stopped.  If it has then updates the dialog.
  428. //-----------------------------------------------------------------------------
  429. VOID OnTimer( HWND hDlg ) 
  430. {
  431.     if( IsWindowEnabled( GetDlgItem( hDlg, IDC_STOP ) ) )
  432.     {
  433.         // We think the sound is playing, so see if it has stopped yet.
  434.         if( !g_pStreamingSound->IsSoundPlaying() ) 
  435.         {
  436.             // Update the UI controls to show the sound as stopped
  437.             EnablePlayUI( hDlg, TRUE );
  438.         }
  439.     }
  440. }
  441.  
  442.  
  443.  
  444.  
  445. //-----------------------------------------------------------------------------
  446. // Name: EnablePlayUI( hDlg,)
  447. // Desc: Enables or disables the Play UI controls 
  448. //-----------------------------------------------------------------------------
  449. VOID EnablePlayUI( HWND hDlg, BOOL bEnable )
  450. {
  451.     if( bEnable )
  452.     {
  453.         EnableWindow( GetDlgItem( hDlg, IDC_LOOP_CHECK ), TRUE );
  454.         EnableWindow( GetDlgItem( hDlg, IDC_PLAY ),       TRUE );
  455.         EnableWindow( GetDlgItem( hDlg, IDC_STOP ),       FALSE );
  456.         SetFocus(     GetDlgItem( hDlg, IDC_PLAY ) );
  457.     }
  458.     else
  459.     {
  460.         EnableWindow( GetDlgItem( hDlg, IDC_LOOP_CHECK ), FALSE );
  461.         EnableWindow( GetDlgItem( hDlg, IDC_PLAY ),       FALSE );
  462.         EnableWindow( GetDlgItem( hDlg, IDC_STOP ),       TRUE );
  463.         SetFocus(     GetDlgItem( hDlg, IDC_STOP ) );
  464.     }
  465. }
  466.  
  467.  
  468.  
  469.  
  470.